package com.hcloud.libupload.task

import android.media.ExifInterface
import android.util.Log
import com.hcloud.libupload.bean.LonLatBean
import com.hcloud.libupload.bean.PutReq
import com.hcloud.libupload.callback.ICreateTaskCallback
import com.hcloud.libupload.callback.IPartSuccessCallback
import com.hcloud.libupload.callback.IProgressCallback
import com.hcloud.libupload.comom.TaskControl
import com.hcloud.libupload.comom.UploadLib
import com.hcloud.libupload.excetion.UploadError
import com.hcloud.libupload.http.Progress
import com.hcloud.libupload.http.RequestTask
import com.hcloud.libupload.request.UploadRequest
import com.hcloud.libupload.utils.*
import retrofit2.HttpException
import java.io.File
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit

open class UploadTask(
    val uploadRequest: UploadRequest,
    val taskControl: TaskControl,
    val iCreateTaskCallback: ICreateTaskCallback
) : IUploadTask, Runnable, Comparable<UploadTask> {

    val config = UploadLib.instance().uploadConfig

    private val max_thread_size = config.maxUploadPartSize
    private val max_queue_size = config.maxQueueSize

    val partPool by lazy {
        ThreadPoolExecutor(
            max_thread_size,
            max_thread_size,
            3,
            TimeUnit.SECONDS,
            ArrayBlockingQueue<Runnable>(max_queue_size)
        )
    }

    var iProgressCallback: IProgressCallback? = null
    var iPartSuccessCallback: IPartSuccessCallback? = null

    val lock = Object()

    var uploadError: Throwable? = null

    val  successPartList = mutableListOf<String>()

    var allPartSize = 0


    var priority = 0

    val file by lazy {
        File(uploadRequest.filePath)
    }

    val progress by lazy {
        Progress()
    }

    val requestTask by lazy {
        RequestTask(taskControl)
    }

    val file2Body by lazy {
        File2Body()
    }

    val fileHash by lazy {
        FileHash(uploadRequest).getFileMD5(file)
    }

    val fileType by lazy {
        getFileType(file)
    }

    val lonLatBean by lazy {
        getLonLat()
    }

    private fun getLonLat(): LonLatBean {
        return if (fileType == 1) {
            val exifInterface = ExifInterface(file.path)
            var longitudeStr =
                exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE)
            var latitudeStr =
                exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE)
            var longitude = PanUtil.score2dimensionality(longitudeStr)
            var latitude = PanUtil.score2dimensionality(latitudeStr)
            LonLatBean(longitude, latitude)
        } else {
            LonLatBean(0.0, 0.0)
        }
    }

    init {
        taskControl.uploadTask = this
    }

    override fun run() {
        try {
            Log.i("upload-sdk", "start task---------")
            prepare()
        } catch (t: Throwable) {
            t.printStackTrace()
            Log.i(
                "upload-sdk",
                "start task--------- error result ${uploadError?.message}--------------${t.message}-----"
            )

            if (uploadRequest.isCancel) {
                uploadError = UploadError(UploadError.UPLOAD_ERROR_10005, "cancel")
            } else {
                if (uploadError == null) {
                    uploadError = t
                }
            }

            callbackError()
        }
    }


    override fun prepare() {
        Thread.sleep(500)

        uploadRequest.isCancel = false
        uploadError = null
        successPartList.clear()
        progress.reset(file)

        if (config.sdkType == 0) {
            register()
        } else {
            commonPut()
        }
    }

    override fun commonPut() {

    }

    override fun register() {
    }


    override fun upload(putReq: PutReq) {
    }

    override fun complete() {
    }

    fun checkError(): Boolean {

        if (uploadRequest.isCancel) {
            uploadError = UploadError(UploadError.UPLOAD_ERROR_10005, "cancel")
        }

        return if (uploadError == null) {
            false
        } else {
            throw uploadError!!
        }
    }

    fun callbackError() {
        runOnUi {
            when (uploadError) {
                is UploadError -> {
                    val serverError = uploadError as UploadError

                    if(uploadError?.message!="cancel"){
                        uploadRequest.requestId = ""
                    }
                    iProgressCallback?.error(
                        uploadRequest,
                        serverError.errorCode,
                        serverError.errorMsg
                    )
                }
                is HttpException -> {
                    val serverError = uploadError as HttpException
                    uploadRequest.requestId = ""
                    iProgressCallback?.error(
                        uploadRequest,
                        serverError.code().toString(),
                        serverError.message()
                    )
                }
                else -> {
                    uploadRequest.requestId = ""
                    iProgressCallback?.error(
                        uploadRequest,
                        UploadError.UPLOAD_ERROR_10006,
                        "error"
                    )
                }
            }
        }
    }

    fun setProgressCallback(iProgressCallback: IProgressCallback) {
        this.iProgressCallback = iProgressCallback
    }

    fun setPartSuccessCallback(iPartSuccessCallback: IPartSuccessCallback) {
        this.iPartSuccessCallback = iPartSuccessCallback
    }

    override fun compareTo(other: UploadTask): Int {
        return if (this.priority > other.priority) 1 else -1
    }

    fun release() {
        partPool.queue.clear()
        partPool.shutdown()
    }

}